package com.dj.service.serviceimpl;

import ca.uhn.fhir.rest.param.StringParam;
import com.dj.bean.EncounterBean;
import com.dj.bean.EncounterHistoryBean;
import com.dj.bean.PatientBean;
import com.dj.constant.FhirContextContstant;
import com.dj.repository.EncounterHistoryRespository;
import com.dj.repository.EncounterRespository;
import com.dj.repository.PatientRespository;
import com.dj.service.EncounterService;
import org.apache.commons.collections4.CollectionUtils;
import org.hl7.fhir.dstu3.model.Encounter;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Meta;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author cyf
 * @description
 * @create 2018-06-27 13:45
 **/

@Service
public class EncounterServiceImpl implements EncounterService {

    private static final Logger logger = LoggerFactory.getLogger(EncounterServiceImpl.class);

    @Autowired
    private EncounterRespository encounterRespository;

    @Autowired
    private PatientRespository patientRespository;

    @Autowired
    private EncounterHistoryRespository encounterHistoryRespository;



    @Transactional
    @Override
    public IdType saveEncounter(Encounter encounter) {
        //将patient转换为json串
        //此处也可以转成xml FhirContextContstant.getXMLParse().encodeResourceToString(patient);
        String content = FhirContextContstant.getParse().encodeResourceToString(encounter);
        //获得实体对象
        EncounterBean encounterBean = getEncounterEntity(encounter, content, FhirContextContstant.INITIAL_VERSION_NUMBER, null);
        //保存到库
        return getSaveRecordResult(content, encounterBean, FhirContextContstant.INITIAL_VERSION_NUMBER);
    }


    @Transactional
    @Override
    public IdType updateEncounter(String id, Encounter encounter) {
        IdType idType = new IdType();

        //判断数据库中是否存在id的就诊
        Optional<EncounterBean> result = null;
        try {
            result = encounterRespository.findById(id);
            logger.info("Current object existence, the encounter id is {}",id);
        } catch (Exception e) {
            logger.error("Exception, Current object existence, the encounter id is {}",id, e);
        }


        if (!result.isPresent()) {
            //记录不存在
            logger.error("encounter id={} is not present!!!", id);
            return idType;
        }

        // 根据id查询的bean
        EncounterBean encounterBean = result.get();
        String version = encounterBean.getVersion();

        // 记录存在
        String content = FhirContextContstant.getParse().encodeResourceToString(encounter);
        //更新 version + 1
        version = String.valueOf(Integer.valueOf(version) + 1);
        return getSaveRecordResult(content, getEncounterEntity(encounter, content, version, encounterBean), version);
    }

    /**
     * 设置数据库表fhir_encounter_record信息
     * @param encounter
     * @param content
     * @param version
     * @param encounterBean
     * @return
     */
    private EncounterBean getEncounterEntity(Encounter encounter, String content, String version, EncounterBean encounterBean) {
        Date date = new Date();
        if (encounterBean == null) {
            encounterBean = new EncounterBean();
            encounterBean.setCreateTime(date);
        }
        encounterBean.setVersion(version);
        encounterBean.setContent(content);
        //记录每次更新的时间
        encounterBean.setParam1(date);

        //患者姓名
        String name = encounter.getSubject().getDisplay();
        encounterBean.setName(name);

        return encounterBean;
    }

    /**
     * 保存记录，用于创建和更新
     * 保存时既保存在当前表中，同时保存在历史表中，历史表保存每次的更新记录
     * @param content
     * @param encounterBean
     * @param version
     * @return
     */
    private IdType getSaveRecordResult(String content, EncounterBean encounterBean, String version) {
        EncounterBean save = null;
        try {
            //保存在当前表
            save = encounterRespository.save(encounterBean);
            logger.info("Save the current version of success");
        } catch (Exception e) {
            logger.error("Exception，Save the current version of error,", e);
        }
        if (save != null) {
            String id = save.getId();
            // 保存历史记录
            if (saveEncounterHistory(content, id, version)) {
                logger.info("Save the historical version of success");
                //resourceType Encounter
                return new IdType("Encounter", id, version);
            }
        }
        return new IdType();
    }

    /**
     * 保存历史记录
     * @param content
     * @param id
     * @param version
     * @return
     */
    private boolean saveEncounterHistory(String content, String id, String version) {

        EncounterHistoryBean encounterHistoryBean = new EncounterHistoryBean();
        encounterHistoryBean.setValidVersionId(id);
        encounterHistoryBean.setVersion(version);
        encounterHistoryBean.setCreateTime(new Date());
        encounterHistoryBean.setContent(content);
        EncounterHistoryBean saveEncounterHistoryBean = null;
        try {
            saveEncounterHistoryBean = encounterHistoryRespository.save(encounterHistoryBean);
        } catch (Exception e) {

            logger.error("saveEncounterHistory error, the cause is {}", e);
        }
        return saveEncounterHistoryBean != null;
    }






    @Override
    public Encounter getByIdAndVersion(String id, String version) {
        EncounterHistoryBean encounterHistoryBean = null;
        try {
            encounterHistoryBean = encounterHistoryRespository.findByValidVersionIdAndVersion(id, version);
            logger.info("Query the specified historical version success");
        } catch (Exception e) {
            logger.error("Exception, Query the specified historical version error, the id is {}, the version is {}",e, version);
        }
        if (encounterHistoryBean != null) {
            return getEncounter(encounterHistoryBean.getContent(), id, version);

        } else {
            logger.info("encounterHistoryRespository.findByValidVersionIdAndVersion Encounter id={} is not exist!!!", id);
            return new Encounter();
        }
    }

    @Override
    public Encounter getByEncounterId(String id) {
        Optional<EncounterBean> result = null;
        try {
            result = encounterRespository.findById(id);
            logger.info("Query the current version success, the encounter id {}", id);
        } catch (Exception e) {
            logger.error("Exception, Query the current version error, the encounter id {}" , e, id);
        }
        if (result.isPresent()) {
            EncounterBean encounterBean = result.get();
            return getEncounter(encounterBean.getContent(), id, encounterBean.getVersion());
        } else {
            logger.info("Encounter getByEncounterId  id={} is not exist!!!", id);
            return new Encounter();
        }
    }

    @Override
    public List<Encounter> getByPatientName(StringParam patientName) {
        String name = patientName.getValue();
        List<EncounterBean> encounterBeanList = null;
        try {
            if (patientName.isExact()) {
                encounterBeanList = encounterRespository.findByName(name);
            } else {
                encounterBeanList = encounterRespository.findByNameLike(name);
            }
            logger.info("Query success based on name");
        } catch (Exception e) {
            logger.error("Exception, According to the name query error, the name is {}", name, e);
        }
        return getEncounterList(encounterBeanList);
    }

    /**
     * 返回集合
     * @param encounterBeanList
     * @return
     */
    private List<Encounter> getEncounterList(List<EncounterBean> encounterBeanList) {
        if (CollectionUtils.isNotEmpty(encounterBeanList)) {
            return encounterBeanList.stream()
                    .filter(encounterBean -> encounterBean != null)
                    .map(encounterBean -> getEncounter(encounterBean.getContent(), encounterBean.getId(), encounterBean.getVersion()))
                    .collect(Collectors.toList());
        } else {
            logger.info("getEncounterList is empty");
            return Collections.emptyList();
        }
    }


    private Encounter getEncounter(String content, String id, String version) {
        Encounter encounter = FhirContextContstant.getParse().parseResource(Encounter.class, content);
        IdType theId = new IdType("Encounter", id, version);
        encounter.setId(theId);
        encounter.setMeta(new Meta().setLastUpdated(getLastUpdatTime(id)));
        return encounter;
    }




    @Transactional
    @Override
    public Boolean deleteEncounter(String id) {

        Optional<EncounterBean> result = null;
        try {
            //先查询是否存在
            result = encounterRespository.findById(id);
        } catch (Exception e) {
            logger.error("Exception, Delete failure according to ID, the id is {}",id, e);
        }

        if (result.isPresent()) {
            try {
                //记录存在 删除当前表id信息
                encounterRespository.deleteById(id);
                logger.info("deleteEncounter is success");
            } catch (Exception e) {
                logger.error("Exception, Delete historical version failure, the id is {}",id, e);
            }
            return true;
        } else {
            //记录不存在
            logger.info("deleteEncounter error,Encounter id={} is not exist!!!", id);
            return false;
        }
    }

    @Override
    public Date getLastUpdatTime(String id) {

        Optional<EncounterBean> result = encounterRespository.findById(id);
        if(!result.isPresent()) {
            logger.info("Encounter findById error, {} is not exist!!!", id);
            return new Date();
        }

        return result.get().getParam1();
    }

    @Override
    public Date getHistoryLastUpdatTime(String id, String version) {
        EncounterHistoryBean encounterHistoryBean = encounterHistoryRespository.findByValidVersionIdAndVersion(id,version);
        if(encounterHistoryBean!=null){
            return encounterHistoryBean.getCreateTime();
        } else {
            return null;
        }
    }

    @Override
    public List<Encounter> getAllEncounterById(String id) {
        List<EncounterHistoryBean> encounterHistoryBeans = encounterHistoryRespository.findByValidVersionId(id);
        return getEncounterLists(encounterHistoryBeans);
    }

    @Override
    public Boolean isExist(String id) {
        Optional<PatientBean> result = patientRespository.findById(id);
        if(result.isPresent()){
            return true;
        } else {
            return false;
        }
    }


    /**
     * 返回历史集合
     * @param encounterHistoryBeans
     * @return
     */
    private List<Encounter> getEncounterLists(List<EncounterHistoryBean> encounterHistoryBeans) {
        if (CollectionUtils.isNotEmpty(encounterHistoryBeans)) {
            logger.info("Query all historical versions of success");
            List<Encounter> list = encounterHistoryBeans.stream()
                    .filter(it -> it != null)
                    .map(it -> getHistroyEncounter(it.getContent(), it.getValidVersionId(), it.getVersion()))
                    .collect(Collectors.toList());

            return list;
        } else {
            logger.info("getEncounterHistoryLists is empty");
            return Collections.emptyList();
        }
    }

    private Encounter getHistroyEncounter(String content, String id, String version) {
        Encounter encounter = FhirContextContstant.getParse().parseResource(Encounter.class, content);
        IdType theId = new IdType("Encounter", id, version);
        encounter.setId(theId);
        encounter.setMeta(new Meta().setLastUpdated(getHistoryLastUpdatTime(id,version)));
        return encounter;
    }


//    @Transactional
//    @Override
//    public Boolean deleteByEncounter(Encounter theEncounter) {
//        logger.info("deleteByEncounter encounter is {}", theEncounter);
//        Boolean retVal = false;
//        IdType theId = theEncounter.getIdElement();
//        String id = theId.getIdPart();
//        String version = theId.getVersionIdPart();
//        EncounterHistoryBean historyEntity = null;
//        try {
//            historyEntity = encounterHistoryRespository.findByValidVersionIdAndVersion(id, version);
//        } catch (Exception e) {
//
//            logger.error("query error ,the cause is " + e);
//        }
//        boolean saveHistory;
//        if (historyEntity == null) {
//            String content = FhirContextContstant.getParse().encodeResourceToString(theEncounter);
//            saveHistory = saveHistory(content, id, version);
//        } else {
//            saveHistory = true;
//        }
//        if (saveHistory) {
//            try {
//                encounterRespository.deleteById(id);
//            } catch (Exception e) {
//                logger.error("delete error ,the cause is " + e);
//            }
//            retVal = true;
//        }
//        return retVal;
//    }







}
